/***********************************************************************************
**  
* @copyright (c) 2010-2019, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
************************************************************************************/
/**
* @file	    mj_net_protocol.h
* @version     
* @brief      
* @author   duye
* @date	    2016-12-19
* @note 
*
* 1. 2016-12-19 duye Created this file
*/
#pragma once

#include <string>
#include <list>
#include <map>
#include <set>
#include <duye_type.h>
#include <duye_buffer.h>
#include <duye_xml.h>

class MJMsgAction {
public:
	// <param_name, param_value>
	typedef std::list<std::string> MJMsgParaList;
	typedef std::map<std::string, std::string> MJMsgParaKeyVal;	

	class MJMsgParaNode {
	public:
		MJMsgParaNode() {}
		MJMsgParaNode(const std::string& value_in) : value(value_in) {}
		MJMsgParaNode(const MJMsgParaList& list_in) : type("list"), list_children(list_in) {}
		MJMsgParaNode(const MJMsgParaKeyVal& map_in) : type("map"), map_children(map_in) {}

		std::string value;
		std::string type;
		// for type = "list"
		MJMsgParaList list_children;	
		// for type = "map"
		MJMsgParaKeyVal map_children;
	};

	// <param_name, param_value>
	typedef std::map<std::string, MJMsgParaNode> MJMsgParaMap;

public:
	MJMsgAction();
	~MJMsgAction();

	// set/get aciton name
	void setName(const std::string& name);
	const std::string& getName() const;

	// set/get action from
	void setFrom(const std::string& from);
	const std::string& getFrom() const;

	// set/get action to
	void setTo(const std::string& to);
	const std::string& getTo() const;

	// add parameter
	void addPara(const std::string& name, const std::string& value);
	void addChildList(const std::string& name, const MJMsgAction::MJMsgParaList& list_data);
	void addChildMap(const std::string& name, const MJMsgAction::MJMsgParaKeyVal& map_data);

	// get parameter value
	std::string getValue(const std::string& name);
	std::string getValue(const std::string& name) const;

	MJMsgParaNode* getParaNode(const std::string& name);
	const MJMsgParaNode* getParaNode(const std::string& name) const;

	bool setValue(const std::string& name, const std::string& value);
	bool setChildList(const std::string& name, const MJMsgAction::MJMsgParaList& list_data);
	bool setChildMap(const std::string& name, const MJMsgAction::MJMsgParaKeyVal& map_data);	

	// get parameters map
	const MJMsgParaMap& getParaMap() const;

	// get order list
	const std::list<std::string>& getOrderParams() const;

private:
	// action name
	std::string m_act_name;
	// action from
	std::string m_act_from;
	// action to
	std::string m_act_to;
	// parameters map
	MJMsgParaMap m_para_map;
	// order param
	std::list<std::string> m_order_params;
};

// <action_name, action>
typedef std::map<std::string, MJMsgAction> MJMsgActionMap;
// <actionname_from_to, duye::XmlElement>
typedef std::map<std::string, duye::XmlElement*> MJMsgActionNodeMap;

class MJMsgFactory {
public:
	typedef enum {
		MJ_PEER_SERVER,
		MJ_PEER_CLIENT,
		MJ_PEER_WEB,
		MJ_PEER_UNKNOWN
	} MJPeerType;

public:
	MJMsgFactory();
	~MJMsgFactory();

	static MJMsgFactory& ins();

	bool init(const std::string& protocol_conf_file, const MJPeerType& type);

	bool fromatMsgXml(const int8* data, const uint32 len, std::list<MJMsgAction>& action_list);
	bool createAction(const std::string& act_name, MJMsgAction& action, const MJPeerType type = MJ_PEER_UNKNOWN);

	bool createMsgXml(const MJMsgAction& action, std::string& msg_xml);
	bool createMsgXml(const std::list<MJMsgAction>& action_list, std::string& msg_xml);

private:
	duye::XmlElement* queryActionNode(const int8* action_name, const int8* from, const int8* to);
	bool queryActionPara(duye::XmlElement* action_node, const int8* para_name);
	void joinAction(const MJMsgAction& action, std::string& msg_xml);
	std::string genNodeKey(const std::string& act_name, const std::string& act_from, const std::string& act_to);
	std::string getPeerName(const MJPeerType type);

private:
	bool m_enable;
	MJPeerType m_peer_type;
	std::string m_peer_name;
	std::string m_to_peer_name;
	std::set<std::string> m_peer_list;
	MJMsgActionNodeMap m_action_node_map;
	duye::XmlDocument m_xml_doc;
};